package cc.siyecao.uid.redis.resposity;

import cc.siyecao.uid.core.resposity.AssignerMode;
import cc.siyecao.uid.core.resposity.WorkerNodeResposity;
import cc.siyecao.uid.core.utils.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.util.Set;

/**
 * 配置
 *
 * @author lyt
 */
@Configuration
@Component
public class UidRedisConfiguration {

    @Value("${uid-generator.redis.database:0}")
    private int database;
    @Value("${uid-generator.redis.host:}")
    private String host;
    @Value("${uid-generator.redis.password:}")
    private String redisPassword;
    @Value("${uid-generator.redis.port:0}")
    private int port;
    @Value("${uid-generator.redis.timeout:6000}")
    private long timeout;
    @Value("${uid-generator.redis.lettuce.shutdown-timeout:6000}")
    private long shutDownTimeout;
    @Value("${uid-generator.redis.lettuce.pool.max-idle:0}")
    private int maxIdle;
    @Value("${uid-generator.redis.lettuce.pool.min-idle:0}")
    private int minIdle;
    @Value("${uid-generator.redis.lettuce.pool.max-active:0}")
    private int maxActive;
    @Value("${uid-generator.redis.lettuce.pool.max-wait:0}")
    private long maxWait;
    @Value("#{'${uid-generator.redis.cluster.nodes:}'.split(',')}")
    private Set<String> nodes;

    @Bean
    @ConditionalOnProperty(value = "uid-generator.assigner-mode", havingValue = AssignerMode.REDIS)
    public LettuceConnectionFactory lettuceConnectionFactory() {
        GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
        genericObjectPoolConfig.setMaxIdle( maxIdle );
        genericObjectPoolConfig.setMinIdle( minIdle );
        genericObjectPoolConfig.setMaxTotal( maxActive );
        genericObjectPoolConfig.setMaxWait( Duration.ofMillis( maxWait ) );
        genericObjectPoolConfig.setTimeBetweenEvictionRuns( Duration.ofMillis( 60 * 1000 ) );
        LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
                .commandTimeout( Duration.ofMillis( timeout ) )
                .shutdownTimeout( Duration.ofMillis( shutDownTimeout ) )
                .poolConfig( genericObjectPoolConfig )
                .build();
        LettuceConnectionFactory factory = null;
        if (StringUtils.isNotEmpty( host )) {
            RedisStandaloneConfiguration redisConfig = new RedisStandaloneConfiguration();
            redisConfig.setDatabase( database );
            redisConfig.setHostName( host );
            redisConfig.setPort( port );
            if (StringUtils.isNotEmpty( redisPassword )) {
                redisConfig.setPassword( RedisPassword.of( redisPassword ) );
            }
            factory = new LettuceConnectionFactory( redisConfig, clientConfig );
        } else if (nodes != null && nodes.size() > 0) {
            RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration( nodes );
            factory = new LettuceConnectionFactory( redisClusterConfiguration, clientConfig );
        }
        return factory;
    }

    @Bean
    @ConditionalOnProperty(value = "uid-generator.assigner-mode", havingValue = AssignerMode.REDIS)
    public RedisTemplate<String, Integer> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
        RedisTemplate<String, Integer> template = new RedisTemplate<>();
        template.setConnectionFactory( lettuceConnectionFactory );
        return template;
    }

    @Bean
    @Primary
    @ConditionalOnProperty(value = "uid-generator.assigner-mode", havingValue = AssignerMode.REDIS)
    public WorkerNodeResposity workerNodeResposity(RedisTemplate<String, Integer> template) {
        return new WorkerNodeRedis( template );
    }

}
